#include "ReverseProxyServer.h"
#include "Poco/Util/Application.h"

ReverseProxyServer::ReverseProxyServer()
    : _helpRequested(false),
      _certFile("c:\\Users\\admin\\local.host.pem"),
    // _certFile("D:\\cpp\\ReverseProxy\\certs\\server\\server.crt"),
    // _keyFile("D:\\cpp\\ReverseProxy\\certs\\server\\server.key"),
    _keyFile("c:\\Users\\admin\\local.host-key.pem"), // Make sure to update the path
    //   _keyFile("c:\\Users\\admin\\local.host-key.pem"),
      _listenPort(443) // Default HTTPS port
{
}

ReverseProxyServer::~ReverseProxyServer() {
}

void ReverseProxyServer::initialize(Poco::Util::Application& self) {
    loadConfiguration(); // Load default configuration file, if any
    ServerApplication::initialize(self);
    // Set custom error handler for SSLManager
    Poco::ErrorHandler::set(&_errorHandler);
}

void ReverseProxyServer::defineOptions(Poco::Util::OptionSet& options) {
    return;
    ServerApplication::defineOptions(options);

    options.addOption(
        Poco::Util::Option("help", "h", "display help information")
            .required(false)
            .repeatable(false)
            .callback(Poco::Util::OptionCallback<ReverseProxyServer>(this, &ReverseProxyServer::handleOption)));

    options.addOption(
        Poco::Util::Option("cert", "c", "Path to server certificate file (PEM format)")
            .required(false)
            .repeatable(false)
            .argument("path")
            .callback(Poco::Util::OptionCallback<ReverseProxyServer>(this, &ReverseProxyServer::handleOption)));

    options.addOption(
        Poco::Util::Option("key", "k", "Path to server private key file (PEM format)")
            .required(false)
            .repeatable(false)
            .argument("path")
            .callback(Poco::Util::OptionCallback<ReverseProxyServer>(this, &ReverseProxyServer::handleOption)));

    options.addOption(
        Poco::Util::Option("port", "p", "Listen port for the HTTPS proxy (default: 443)")
            .required(false)
            .repeatable(false)
            .argument("port_number")
            .callback(Poco::Util::OptionCallback<ReverseProxyServer>(this, &ReverseProxyServer::handleOption)));
}

void ReverseProxyServer::handleOption(const std::string& name, const std::string& value) {
    if (name == "help") {
        _helpRequested = true;
    } else if (name == "cert") {
        _certFile = value;
    } else if (name == "key") {
        _keyFile = value;
    } else if (name == "port") {
        try {
            _listenPort = std::stoi(value);
        } catch (const std::exception& e) {
            std::cerr << "Invalid port number: " << value << ". Using default 443." << std::endl;
        }
    }
}

int ReverseProxyServer::main(const std::vector<std::string>& args) {
    if (_helpRequested) {
        Poco::Util::HelpFormatter hf(options());
        hf.setHeader("Reverse Proxy Server");
        hf.setUsage("options");
        hf.setHeader("A simple SSL reverse proxy using POCO C++ Libraries.");
        hf.format(std::cout);
        return Poco::Util::Application::EXIT_OK;
    }

    if (_certFile.empty() || _keyFile.empty()) {
        std::cerr << "Error: Certificate and key file paths are required. Use --cert and --key options." << std::endl;
        return Poco::Util::Application::EXIT_USAGE;
    }

    try {
        // Initialize SSL
        // Poco::Net::SSLManager::initializeSSL();
        bool is_server = true;
        bool handleErrorsOnServerSide = true;
        Poco::SharedPtr<Poco::Net::PrivateKeyPassphraseHandler> pConsoleHandler = new Poco::Net::KeyConsoleHandler(is_server);
		Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> pInvalidCertHandler = new Poco::Net::ConsoleCertificateHandler(handleErrorsOnServerSide);
		// Poco::Net::Context::Ptr pContext = new Poco::Net::Context(Context::SERVER_USE, "any.pem", "any.pem", "rootcert.pem", Context::VERIFY_RELAXED, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
		// Poco::Net::SSLManager::instance().initializeServer(pConsoleHandler, pInvalidCertHandler, pContext);
        std::cout << "certFile:" << _certFile << "\n";
        std::cout << "keyFile:" << _keyFile << "\n";
        // Load your server certificate and private key
        Poco::Net::Context::Ptr pContext = new Poco::Net::Context(
            Poco::Net::Context::TLS_SERVER_USE, // Using TLS 1.2 for server
            _keyFile,          // Private key file
            _certFile,         // Certificate file
            "",                // CA certificate file (optional for client cert validation)
            Poco::Net::Context::VERIFY_NONE, // No client certificate verification for simplicity
            9,                 // Session ID context (any non-zero value)
            true               // Use default ciphers
        );

        // Optionally, register a custom certificate handler if you need specific logic
        // for handling untrusted client certs or certificate errors.
        // For a server, you usually don't accept client certs, so AcceptCertificateHandler
        // is more for client-side SSL. KeyConsoleHandler is for password protected keys.
        // If your key is password protected:
        // Poco::Net::SSLManager::instance().setPrivateKeyPassphraseHandler(new Poco::Net::KeyConsoleHandler(true));

        // Poco::Net::SSLManager::instance().setDefaultServerContext(pContext);
		Poco::Net::SSLManager::instance().initializeServer(pConsoleHandler, pInvalidCertHandler, pContext);

        // Set up the HTTPS server socket
        Poco::Net::SecureServerSocket svs(_listenPort, 128, pContext);
        Poco::Net::HTTPServerParams::Ptr pParams = new Poco::Net::HTTPServerParams;
        pParams->setMaxQueued(100);
        pParams->setMaxThreads(16); // Adjust thread count based on your needs

        // Create and start the HTTPS server
        Poco::Net::HTTPServer srv(new ReverseProxyRequestHandlerFactory(), svs, pParams);
        srv.start();
        std::cout << "SSL Reverse Proxy Server started on port " << _listenPort << std::endl;
        std::cout << "  - Web Server Backend: local.host:8080" << std::endl;
        std::cout << "  - WebSocket Backend:  local.host:8081/echo" << std::endl;
        std::cout << "Press Ctrl+C to stop..." << std::endl;

        waitForTerminationRequest(); // Wait for stop signal
        srv.stop();
        std::cout << "SSL Reverse Proxy Server stopped." << std::endl;

        // Poco::Net::SSLManager::uninitializeSSL(); // Clean up SSL
    } catch (Poco::Exception& exc) {
        std::cerr << "Poco Exception: " << exc.displayText() << std::endl;
        return Poco::Util::Application::EXIT_SOFTWARE;
    } catch (std::exception& exc) {
        std::cerr << "Standard Exception: " << exc.what() << std::endl;
        return Poco::Util::Application::EXIT_SOFTWARE;
    } catch (...) {
        std::cerr << "Unknown Exception." << std::endl;
        return Poco::Util::Application::EXIT_SOFTWARE;
    }

    return Poco::Util::Application::EXIT_OK;
}

// Global error handler instance
static MyErrorHandler _errorHandler;